﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Xin478.CSWork.Client
{

    public class MyTabCtrl : TabControlEx
    {
        Rectangle cachedDisplayRect;
        int tabPageMargin = 2;          //选项卡间隔
        const int CLOSE_SIZE = 9;       //关闭图标大小
        int mx, my;

        Color color1 = Color.FromArgb(219, 235, 255);//tab起始渐变
        Color color2 = Color.FromArgb(209, 231, 255);//tab结束渐变
        Color color3 = Color.FromArgb(119, 157, 216);//tab选定边框
        Color color4 = Color.FromArgb(185, 248, 255);//tab选定右边框
        Color color5 = Color.FromArgb(91, 159, 231);//tab未选定起始渐变
        Color color6 = Color.FromArgb(113, 169, 240);//tab未选定结束渐变
        Color color7 = Color.FromArgb(91, 159, 231);//tab未选定边框
        Color color8 = Color.FromArgb(60, 101, 175);//tab选定关闭激活
        Color color9 = Color.FromArgb(198, 223, 253);//tab未选定关闭激活
        Color color10 = Color.FromArgb(149, 175, 201);//tab选定关闭
        Color color11 = Color.FromArgb(144, 189, 244);//tab未选定关闭

        Color c1 = Color.FromArgb(0, 0, 0, 0);//选项卡背景渐变上
        Color c2 = Color.FromArgb(30, 0, 0, 0);//选项卡背景渐变下


        public int TabPageMargin { get { return tabPageMargin; } set { tabPageMargin = value; } }
        public event CancelEventHandler TabPageClosing;
        public event EventHandler TabPageClosed;

        public MyTabCtrl() : base()
        {
            this.Alignment = TabAlignment.Top;
            this.MouseDown += new MouseEventHandler(MyTabCtrl_MouseDown);
            this.MouseMove += new MouseEventHandler(MyTabCtrl_MouseMove);
        }

        void MyTabCtrl_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                int x = e.X, y = e.Y;

                Rectangle myTabRect = this.GetTabRect(this.SelectedIndex);

                myTabRect.Offset(myTabRect.Width - (CLOSE_SIZE + 3), 2);
                myTabRect.Width = CLOSE_SIZE;
                myTabRect.Height = CLOSE_SIZE;

                if (x > myTabRect.X && x < myTabRect.Right && y > myTabRect.Y && y < myTabRect.Bottom)
                {
                    if (TabPageClosing != null)
                    {
                        CancelEventArgs arg = new CancelEventArgs();
                        TabPageClosing(sender, arg);
                        if (arg.Cancel) return;
                    }
                    this.TabPages.Remove(this.SelectedTab);

                    if (TabPageClosed != null) TabPageClosed(sender, null);
                }
            }
        }

        void MyTabCtrl_MouseMove(object sender, MouseEventArgs e)
        {
            mx = e.X;
            my = e.Y;
        }

        protected override void OnResize(EventArgs e)
        {
            ResetCachedDisplayRect();
            base.OnResize(e);
        }

        void ResetCachedDisplayRect()
        {
            this.cachedDisplayRect = base.DisplayRectangle;
            this.cachedDisplayRect.X = 0;
            this.cachedDisplayRect.Width += 8;
            this.cachedDisplayRect.Y-=2;
            this.cachedDisplayRect.Height += 6;
        }

        protected override void DrawTabPages(Graphics g)
        {
            Rectangle tabRect;
            Point cusorPoint = PointToClient(MousePosition);
            bool hover;
            bool selected;
            bool hasSetClip = false;

            IntPtr upDownButtonHandle = UpDownButtonHandle;
            bool hasUpDown = upDownButtonHandle != IntPtr.Zero;
            if (hasUpDown)
            {
                if (NativeMethods.IsWindowVisible(upDownButtonHandle))
                {
                    NativeMethods.RECT upDownButtonRect = new NativeMethods.RECT();
                    NativeMethods.GetWindowRect(upDownButtonHandle, ref upDownButtonRect);
                    Rectangle upDownRect = Rectangle.FromLTRB(
                        upDownButtonRect.Left,
                        upDownButtonRect.Top,
                        upDownButtonRect.Right,
                        upDownButtonRect.Bottom);
                    upDownRect = RectangleToClient(upDownRect);

                    upDownRect.Y = 0;
                    upDownRect.Height = ClientRectangle.Height;
                    g.SetClip(upDownRect, CombineMode.Exclude);
                    hasSetClip = true;
                }
            }

            Pen pen = new Pen(color3);
            for (int index = 0; index < base.TabCount; index++)
            {
                TabPage page = TabPages[index];

                tabRect = GetTabRect(index);
                hover = tabRect.Contains(cusorPoint);
                selected = SelectedIndex == index;
                using (GraphicsPath path = CreateTabPath(tabRect, index))
                {
                    if (selected)
                    {
                        using (LinearGradientBrush brush = new LinearGradientBrush(tabRect, Color.White, Color.LightGray, LinearGradientMode.Vertical))
                        {
                            g.FillPath(brush, path);
                        }

                        Rectangle rect1 = new Rectangle(tabRect.X, tabRect.Y + Radius / 2, tabRect.Width, tabRect.Height - Radius / 2);
                        using (LinearGradientBrush brush = new LinearGradientBrush(rect1, color1, color2, LinearGradientMode.Vertical))
                        {
                            g.FillRectangle(brush, rect1);
                        }

                        path.CloseFigure();
                        pen.Color = color3;
                        g.DrawLines(pen, path.PathPoints);
                        pen.Color = color4;
                        g.DrawLine(pen, tabRect.Right - 1, tabRect.Y + Radius / 2 - 1, tabRect.Right - 1, tabRect.Height - 1);
                        
                    }
                    else
                    {
                        path.AddLine(tabRect.Right, tabRect.Bottom, tabRect.X, tabRect.Bottom);
                        using (LinearGradientBrush brush = new LinearGradientBrush(tabRect, color5, color6, LinearGradientMode.Vertical))
                        {
                            g.FillPath(brush, path);
                        }
                        
                        pen.Color = color7;
                        g.DrawLines(pen, path.PathPoints);


                        DrawBackgroundDark(g, tabRect.X, tabRect.Bottom, tabRect.Width);
                    }

                    if (index > 0 && mx > tabRect.X && mx < tabRect.Right && my > tabRect.Y && my < tabRect.Bottom)
                    {
                        Color closeColor;
                        int x2 = tabRect.Right - 4, y1 = tabRect.Y + (tabRect.Height - CLOSE_SIZE) / 2;
                        int x1 = x2 - CLOSE_SIZE, y2 = y1 + CLOSE_SIZE;

                        if (mx >= x1 && mx <= x2 && my >= y1 && my <= y2)
                            closeColor = selected ? color8 : color9;
                        else
                            closeColor = selected ? color10 : color11;
                                                
                        using (Pen objpen = new Pen(closeColor, 2))
                        {
                            g.DrawLine(objpen, x1, y1, x2, y2);// "\"线                            
                            g.DrawLine(objpen, x1, y2, x2, y1);// "/"线
                        }
                    }
                }

                Rectangle textRect = tabRect;
                TextRenderer.DrawText(g, page.Text, page.Font, textRect, page.ForeColor);
            }
            if (hasSetClip)
            {
                g.ResetClip();
            }
        }

        void DrawBackgroundDark(Graphics g, int x,int bottom,int width)
        {
            Rectangle r = new Rectangle(x, bottom - 6, width, 6);
            using (LinearGradientBrush brush = new LinearGradientBrush(r, c1, c2, LinearGradientMode.Vertical))
            {
                g.FillRectangle(brush, r);
            }
        }

        public new Rectangle GetTabRect(int index)
        {
            Rectangle rect = base.GetTabRect(index);
            rect.X -= 2;
            rect.Y -= 2;
            rect.Height += 2;
            rect.Width -= TabPageMargin;
            return rect;
        }

        public override Rectangle DisplayRectangle
        {
            get
            {
                if (this.cachedDisplayRect.IsEmpty)
                {
                    ResetCachedDisplayRect();
                }
                return this.cachedDisplayRect;
            }
        }

        protected override void DrawDrawBackgroundAndHeader(Graphics g)
        {
            int x = 0;
            int y = 0;
            int width = ClientRectangle.Width;
            int height = ClientRectangle.Height - DisplayRectangle.Height;

            Rectangle headerRect = new Rectangle(x, y, width, height);
            Color backColor = Enabled ? BackColor : SystemColors.Control;

            using (SolidBrush brush = new SolidBrush(backColor))
            {
                g.FillRectangle(brush, ClientRectangle);

                g.FillRectangle(brush, headerRect);
                DrawBackgroundDark(g, headerRect.X, headerRect.Bottom, headerRect.Width);
                brush.Dispose();
            }
        }

        protected override void DrawBorder(Graphics g)
        {
            if (SelectedIndex != -1)
            {
                Rectangle tabRect = GetTabRect(SelectedIndex);
                Rectangle clipRect = ClientRectangle;
                Point[] points = new Point[6];

                IntPtr upDownButtonHandle = UpDownButtonHandle;
                bool hasUpDown = upDownButtonHandle != IntPtr.Zero;
                if (hasUpDown)
                {
                    if (NativeMethods.IsWindowVisible(upDownButtonHandle))
                    {
                        NativeMethods.RECT upDownButtonRect = new NativeMethods.RECT();
                        NativeMethods.GetWindowRect(
                            upDownButtonHandle,
                            ref upDownButtonRect);
                        Rectangle upDownRect = Rectangle.FromLTRB(
                            upDownButtonRect.Left,
                            upDownButtonRect.Top,
                            upDownButtonRect.Right,
                            upDownButtonRect.Bottom);
                        upDownRect = RectangleToClient(upDownRect);

                        tabRect.X = tabRect.X > upDownRect.X ?
                            upDownRect.X : tabRect.X;
                        tabRect.Width = tabRect.Right > upDownRect.X ?
                            upDownRect.X - tabRect.X : tabRect.Width;
                    }
                }

                points[0] = new Point(tabRect.X, tabRect.Bottom);
                points[1] = new Point(clipRect.X, tabRect.Bottom);
                points[2] = new Point(clipRect.X, clipRect.Bottom - 1);
                points[3] = new Point(clipRect.Right - 1, clipRect.Bottom - 1);
                points[4] = new Point(clipRect.Right - 1, tabRect.Bottom);
                points[5] = new Point(tabRect.Right, tabRect.Bottom);
                using (Pen pen = new Pen(BorderColor))
                {
                    g.DrawLines(pen, points);
                    pen.Color = Color.FromArgb(209, 231, 255);
                    g.DrawLine(pen, tabRect.X, tabRect.Height + 2, tabRect.Right - 1, tabRect.Height + 2);
                }
            }
        }

        internal override void RenderButton(Graphics g, Rectangle rect, Color baseColor, Color borderColor, Color arrowColor, ArrowDirection direction)
        {
            using (SolidBrush brush = new SolidBrush(arrowColor))
            {
                RenderArrowInternal(g, rect, direction, brush);
            }
        }

        GraphicsPath CreateTabPath(Rectangle rect, int index)
        {
            GraphicsPath path = new GraphicsPath();
            if (SelectedIndex != index)
            {
                rect.Y++;
                rect.Height--;
            }
            if (index == 0)
            {
                path.AddLine(rect.X, rect.Bottom, rect.X, rect.Y);
            }
            else
            {
                path.AddLine(rect.X, rect.Bottom, rect.X, rect.Y + Radius / 2);
                path.AddArc(rect.X, rect.Y, Radius, Radius, 180F, 90F);
            }


            path.AddArc(rect.Right - Radius, rect.Y, Radius, Radius, 270F, 90F);
            path.AddLine(rect.Right, rect.Bottom, rect.Right, rect.Y + Radius);
            //path.CloseFigure();
            return path;
        }
    }
}
